package net.f5.image;

import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.MemoryImageSource;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class Bmp {
    int iDataOffset;

    int pixel[] = null;

    BufferedInputStream imageFile;

    int bfSize;

    int bfOffBits;

    int biSize;

    int biWidth;

    int biHeight;

    int biPlanes;

    int biBitCount;

    int biCompression;

    int biSizeImage;

    int biXPelsPerMeter;

    int biYPelsPerMeter;

    int biClrUsed;

    int biClrImportant;

    public Bmp(final String fileName) {
        try {
            this.imageFile = new BufferedInputStream(new FileInputStream(fileName));
            readBitmapFileHeader();
            readBitmapInfoHeader();
            this.pixel = new int[this.biWidth * this.biHeight];
            int padding = 3 * this.biWidth % 4;
            if (padding > 0) {
                padding = 4 - padding;
            }
            int offset;
            for (int y = 1; y <= this.biHeight; y++) {
                offset = (this.biHeight - y) * this.biWidth;
                for (int x = 0; x < this.biWidth; x++) {
                    this.pixel[offset + x] = readPixel();
                }
                for (int x = 0; x < padding; x++) {
                    this.imageFile.read();
                }
            }
        } catch (final Exception e) {
            System.out.println(fileName + " is not a true colour file.");
            System.exit(1);
        }
    }

    public Image getImage() {
        MemoryImageSource mis;
        mis = new MemoryImageSource(this.biWidth, this.biHeight, this.pixel, 0, this.biWidth);
        return Toolkit.getDefaultToolkit().createImage(mis);
    }

    void readBitmapFileHeader() throws Exception {
        if (this.imageFile.read() != 'B')
            throw new Exception();
        if (this.imageFile.read() != 'M')
            throw new Exception();
        this.bfSize = readInt();
        readInt(); // ignore 4 bytes reserved
        this.bfOffBits = readInt();
    }

    void readBitmapInfoHeader() throws Exception {
        this.biSize = readInt();
        this.biWidth = readInt();
        this.biHeight = readInt();
        this.biPlanes = readShort();
        this.biBitCount = readShort();
        if (this.biBitCount != 24)
            throw new Exception();
        this.biCompression = readInt();
        this.biSizeImage = readInt();
        this.biXPelsPerMeter = readInt();
        this.biYPelsPerMeter = readInt();
        this.biClrUsed = readInt();
        this.biClrImportant = readInt();
    }

    int readInt() throws IOException {
        int retVal = 0;

        for (int i = 0; i < 4; i++) {
            retVal += (this.imageFile.read() & 0xff) << 8 * i;
        }
        return retVal;
    }

    int readPixel() throws IOException {
        int retVal = 0;

        for (int i = 0; i < 3; i++) {
            retVal += (this.imageFile.read() & 0xff) << 8 * i;
        }
        return retVal | 0xff000000;
    }

    int readShort() throws IOException {
        int retVal;

        retVal = this.imageFile.read() & 0xff;
        retVal += (this.imageFile.read() & 0xff) << 8;
        return retVal;
    }
}
